﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows.Data;
using System.Windows;
using System.Collections;
using System.Windows.Controls;
using Sinacor.Infra.UI.Settings;
using System.Globalization;
using PSE.Framework.UI.Settings;

namespace Sinacor.Infra.UI.Controls.SmartClient.DataGrid
{
    public partial class SinacorDataGrid : Microsoft.Windows.Controls.DataGrid, IConfigurationComponent<SinacorConfigurationObjectType>, IItemsControlDragSource, IItemsControlDropTarget
    {
        private Dictionary<string, object> _extensionData = new Dictionary<string,object>();

        #region Construtores
        public SinacorDataGrid() : base()
        {
            // Colunas
            _columns = new DataGridColumnCollection(this);

            // Exibir/ocultar colunas
            this.SetValue(ChangeVisibilityColumnsKey, new ListCollectionView(this.Columns));
            this.ChangeVisibilityColumns.SortDescriptions.Add(new SortDescription("DisplayIndex", ListSortDirection.Ascending));
            this.ChangeVisibilityColumns.Filter = new Predicate<object>(delegate(object item) { return ((IDataGridColumn)item).CanUserChangeVisibility; });

            this.Loaded += new RoutedEventHandler(SinacorDataGrid_Loaded);
            this.Unloaded += new RoutedEventHandler(SinacorDataGrid_Unloaded);

            // BufferedEvent
            _bufferedSelectionChangedEventManager = new BufferedEventManager<SelectionChangedEventArgs>();
            this.SelectionChanged += _bufferedSelectionChangedEventManager.EventCapturer;
            _bufferedSelectionChangedEventManager.AddBufferedEventListener(this, OnBufferedSelectionChanged);

            // Adicionando input bindings de exportação
            this.InputBindings.Add(new KeyBinding(ExportCommands.CopyAllClipboard, new KeyGesture(Key.C, ModifierKeys.Control | ModifierKeys.Shift)));

            // Registrando command bindings de seleção
            this.CommandBindings.Add(new CommandBinding(SelectionCommands.SelectFirstItem, new ExecutedRoutedEventHandler(SelectFirstItemCommand_Executed), new CanExecuteRoutedEventHandler(SelectFirstItemCommand_CanExecute)));
            this.CommandBindings.Add(new CommandBinding(SelectionCommands.SelectNextItem, new ExecutedRoutedEventHandler(SelectNextItemCommand_Executed), new CanExecuteRoutedEventHandler(SelectNextItemCommand_CanExecute)));
            this.CommandBindings.Add(new CommandBinding(SelectionCommands.SelectPreviousItem, new ExecutedRoutedEventHandler(SelectPreviousItemCommand_Executed), new CanExecuteRoutedEventHandler(SelectPreviousItemCommand_CanExecute)));
            this.CommandBindings.Add(new CommandBinding(SelectionCommands.SelectLastItem, new ExecutedRoutedEventHandler(SelectLastItemCommand_Executed), new CanExecuteRoutedEventHandler(SelectLastItemCommand_CanExecute)));

            // Registrando command bindings de exportação
            this.CommandBindings.Add(new CommandBinding(ExportCommands.ExportExcel, new ExecutedRoutedEventHandler(ExportExcelCommand_Executed), new CanExecuteRoutedEventHandler(ExportExcelCommand_CanExecute)));
            this.CommandBindings.Add(new CommandBinding(ExportCommands.ExportAllExcel, new ExecutedRoutedEventHandler(ExportAllExcelCommand_Executed), new CanExecuteRoutedEventHandler(ExportAllExcelCommand_CanExecute)));
            this.CommandBindings.Add(new CommandBinding(ExportCommands.CopyAllClipboard, new ExecutedRoutedEventHandler(CopyAllClipboardCommand_Executed), new CanExecuteRoutedEventHandler(CopyAllClipboardCommand_CanExecute)));

            DragDropManager dragDropManager = new DragDropManager(this);
        }

        static SinacorDataGrid()
        {
            ItemsSourceProperty.OverrideMetadata(typeof(SinacorDataGrid), new FrameworkPropertyMetadata(null, OnCoerceItemsSourceProperty));
        }
        #endregion

        #region Columns
        private DataGridColumnCollection _columns;
        /// <summary>
        /// Colunas do DataGrid 
        /// </summary>
        public new DataGridColumnCollection Columns
        {
            get { return _columns; }
        }

        /// <summary>
        /// Colunas internas do DataGrid
        /// </summary>
        internal ObservableCollection<Microsoft.Windows.Controls.DataGridColumn> InternalColumns
        {
            get { return base.Columns; }
        }

        #region ChangeVisibilityColumns
        protected static readonly DependencyPropertyKey ChangeVisibilityColumnsKey = DependencyProperty.RegisterReadOnly("ChangeVisibilityColumns", typeof(ListCollectionView), typeof(SinacorDataGrid), new FrameworkPropertyMetadata(null, null, CoerceChangeVisibilityColumns));
        public static readonly DependencyProperty ChangeVisibilityColumnsProperty = ChangeVisibilityColumnsKey.DependencyProperty;
        /// <summary>
        /// Colunas que o usuário pode alterar a visibilidade do DataGrid
        /// </summary>
        public ListCollectionView ChangeVisibilityColumns
        {
            get { return (ListCollectionView)GetValue(ChangeVisibilityColumnsProperty); }
        }

        private static object CoerceChangeVisibilityColumns(DependencyObject d, object value)
        {
            if (value != null)
            {
                ((ListCollectionView)value).Refresh();
            }

            return value;
        }
        #endregion

        #region CanHideColumn
        protected static readonly DependencyPropertyKey CanHideColumnKey = DependencyProperty.RegisterReadOnly("CanHideColumn", typeof(bool), typeof(SinacorDataGrid), new FrameworkPropertyMetadata(true, null, CoerceCanHideColumn));
        public static readonly DependencyProperty CanHideColumnProperty = CanHideColumnKey.DependencyProperty;
        /// <summary>
        /// Indica se o usuário ainda pode esconder as colunas
        /// </summary>
        public bool CanHideColumn
        {
            get { return (bool)GetValue(CanHideColumnProperty); }
        }

        private static object CoerceCanHideColumn(DependencyObject d, object value)
        {
            SinacorDataGrid grid = (SinacorDataGrid)d;

            value = (from c in grid.Columns where c.Visibility == Visibility.Visible select c.DisplayIndex).Count() > 1;

            return value;
        }
        #endregion

        #endregion
       
        #region Tratamento de eventos

        private void SinacorDataGrid_Loaded(object sender, RoutedEventArgs e)
        {
            _extensionData.Clear();

            SinacorWindow window = Window.GetWindow(this) as SinacorWindow;
            if (window != null)
                _extensionData.Add("SinacorModule", window.ModuleId);

            _bufferedSelectionChangedEventManager.Start();
        }
        private void SinacorDataGrid_Unloaded(object sender, RoutedEventArgs e)
        {
            _extensionData.Clear();

            _bufferedSelectionChangedEventManager.Stop();
        }

        protected override void OnLoadingRow(Microsoft.Windows.Controls.DataGridRowEventArgs e)
        {
            base.OnLoadingRow(e);

            // Aplica estilo após exibir linha
            ((DataGridRow)e.Row).ApplyStyle();
        }

        /// <summary>
        /// Os métodos OnCoerceItemsSourceProperty e OnItemsSourceChanged abaixo servem para
        /// salvar e restaurar a ordenação das colunas, isso porque a classe base limpa a 
        /// ordenação todas vez que o ItemsSource muda
        /// </summary>
        private Dictionary<string, ListSortDirection?> _savedSortDirections = null;

        private static object OnCoerceItemsSourceProperty(DependencyObject d, object value)
        {
            SinacorDataGrid dataGrid = (SinacorDataGrid)d;

            // Salva a ordenação das colunas antes de alterar o ItemsSource
            if (dataGrid.ItemsSource != value)
            {
                dataGrid._savedSortDirections = new Dictionary<string, ListSortDirection?>();

                foreach (Microsoft.Windows.Controls.DataGridColumn c in dataGrid.Columns)
                {
                    dataGrid._savedSortDirections.Add(((IDataGridColumn)c).Name, c.SortDirection);
                }
            }

            return value;
        }

        protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {
            base.OnItemsSourceChanged(oldValue, newValue);

            // Restaura a ordenação após alterar o ItemsSource
            if (this._savedSortDirections != null)
            {
                foreach (KeyValuePair<string, ListSortDirection?> s in this._savedSortDirections)
                {
                    this.Columns[s.Key].SortDirection = s.Value;
                }

                this._savedSortDirections = null;

                this.RefreshSort();
            }
        }

        protected override void OnRowEditEnding(Microsoft.Windows.Controls.DataGridRowEditEndingEventArgs e)
        {
            // TODO: Verificar se todas as colunas com IsRequired=True estão com os campos definidos no Binding 
            // preenchidos, se alguma não estiver, executar os passos abaixo:

            // 1. Setar coluna como corrente (this.CurrentColumn = dg.Columns[x];)
            // 2. Escrolar até a coluna (this.ScrollIntoView(this.CurrentItem, this.Columns[x]);)
            // 3. Iniciar edição na célula (this.BeginEdit();)
            // 4. Verificar se os controles da célula estão IsLoaded=true
            // 5. Se não estiver, executar DoEvents
            // 6. Executar validação na célula
            // 7. Não disparar e cancelar o evento (e.Cancel = true;)

            // Se todas as células estiverem preenchidas, dispara o evento

            base.OnRowEditEnding(e);
        }
        #endregion

        #region Selection

        #region ConfirmSelectionEvent
        public static readonly RoutedEvent ConfirmSelectionEvent = EventManager.RegisterRoutedEvent("ConfirmSelection", RoutingStrategy.Bubble, typeof(ItemEventHandler), typeof(SinacorDataGrid));
        /// <summary>
        /// Evento disparado quando o usuário confima a seleção de um item
        /// </summary>
        public event ItemEventHandler ConfirmSelection
        {
            add { AddHandler(ConfirmSelectionEvent, value); }
            remove { RemoveHandler(ConfirmSelectionEvent, value); }
        }

        /// <summary>
        /// Dispara o evento <c>ConfirmSelection</c>
        /// </summary>
        /// <param name="element">Elemento que vai disparar o evento</param>
        /// <param name="index">Índice do item</param>
        /// <param name="item">Item</param>
        protected virtual void OnConfirmSelection(int index, object item)
        {
            ItemEventArgs e = new ItemEventArgs(ConfirmSelectionEvent, this, new ItemInfo(index, item));
            this.RaiseEvent(e);
        }
        #endregion

        #region BufferedSelectionChangedEvent
        private BufferedEventManager<SelectionChangedEventArgs> _bufferedSelectionChangedEventManager;

        public static readonly RoutedEvent BufferedSelectionChangedEvent = EventManager.RegisterRoutedEvent("BufferedSelectionChanged", RoutingStrategy.Bubble, typeof(BufferedEventHandler<SelectionChangedEventArgs>), typeof(SinacorDataGrid));
        /// <summary>
        /// Evento buferizado de SelectionChanged
        /// </summary>
        public event BufferedEventHandler<SelectionChangedEventArgs> BufferedSelectionChanged
        {
            add { AddHandler(BufferedSelectionChangedEvent, value); }
            remove { RemoveHandler(BufferedSelectionChangedEvent, value); }
        }

        protected virtual void OnBufferedSelectionChanged(object sender, SelectionChangedEventArgs originalEventArgs, int eventCount)
        {
            BufferedEventArgs<SelectionChangedEventArgs> e = new BufferedEventArgs<SelectionChangedEventArgs>(BufferedSelectionChangedEvent, originalEventArgs, eventCount);
            this.RaiseEvent(e);
        }
        #endregion

        #endregion

        #region Row Generation
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is DataGridRow;
        }

        protected override System.Windows.DependencyObject GetContainerForItemOverride()
        {
            return new DataGridRow();
        }
        #endregion

        #region Sort

        #region Sorting
        public new event Microsoft.Windows.Controls.DataGridSortingEventHandler Sorting;

        /// <summary>
        /// Protected method which raises the sorting event and does default sort
        /// </summary>
        /// <param name="eventArgs"></param>
        protected override void OnSorting(Microsoft.Windows.Controls.DataGridSortingEventArgs eventArgs)
        {
            eventArgs.Handled = false;
            if (Sorting != null)
            {
                Sorting(this, eventArgs);
            }

            if (!eventArgs.Handled)
            {
                SortColumn(eventArgs.Column, (Keyboard.Modifiers & ModifierKeys.Shift) != ModifierKeys.Shift);
            }
        }
        #endregion

        #region SortExpression
        public static readonly DependencyProperty SortExpressionProperty = DependencyProperty.Register("SortExpression", typeof(string), typeof(SinacorDataGrid), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSortExpressionChanged)));
        /// <summary>
        /// Expressão utilizada na ordenação
        /// </summary>
        public string SortExpression
        {
            get { return (string)GetValue(SortExpressionProperty); }
            set { SetValue(SortExpressionProperty, value); }
        }

        private static void OnSortExpressionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            SinacorDataGrid dataGrid = (SinacorDataGrid)d;
            dataGrid.RefreshSort();
        }
        #endregion

        #region RefreshSort
        private void RefreshSort()
        {
            ListCollectionView cv = CollectionViewSource.GetDefaultView(this.ItemsSource) as ListCollectionView;

            if (cv != null)
            {
                Type itemType = this.GetItemType();

                // Verifica se existe pelo menos uma coluna com ordenação
                if (!string.IsNullOrEmpty(this.SortExpression) && itemType != null)
                {
                    // Se não existir, cria um CustomSort
                    cv.CustomSort = Dynamite.ComparerBuilder.CreateTypeComparer(itemType, this.SortExpression);
                }
                else
                {
                    // Se nenhuma coluna estiver ordenada, limpa CustomSort
                    cv.CustomSort = null;
                }
            }
        }
        #endregion

        #region SortColumn
        private void SortColumn(Microsoft.Windows.Controls.DataGridColumn column, bool clearExistingSortDescriptions)
        {
            ListSortDirection? sortDirection = column.SortDirection;

            if (clearExistingSortDescriptions)
            {
                foreach (Microsoft.Windows.Controls.DataGridColumn c in this.Columns)
                {
                    if (c.SortDirection != null && c != column)
                    {
                        c.SortDirection = null;
                    }
                }
            }

            if (!string.IsNullOrEmpty(column.SortMemberPath))
            {
                if (sortDirection == null)
                {
                    column.SortDirection = ListSortDirection.Ascending;
                }
                else if (sortDirection == ListSortDirection.Ascending)
                {
                    column.SortDirection = ListSortDirection.Descending;
                }
                else if (sortDirection == ListSortDirection.Descending)
                {
                    column.SortDirection = null;
                }
            }

            StringBuilder sortExpression = new StringBuilder();

            // Captura todas as colunas de tem ordenação
            List<Microsoft.Windows.Controls.DataGridColumn> sortedColumns = (
                from c in this.Columns
                where
                    c.SortDirection != null &&
                    !string.IsNullOrEmpty(c.SortMemberPath)
                orderby ((IDataGridColumn)c).SortIndex
                select c).ToList();

            for (int i = 0; i < sortedColumns.Count; i++)
            {
                Microsoft.Windows.Controls.DataGridColumn c = sortedColumns[i];

                if (i > 0)
                    sortExpression.Append(", ");

                sortExpression.Append(c.SortMemberPath.Replace(",", " " + c.SortDirection.ToString().ToUpper() + ","));
                sortExpression.Append(" " + c.SortDirection.ToString().ToUpper());
            }

            this.SortExpression = sortExpression.ToString();
        }
        #endregion

        #endregion

        #region ApplyingStyle
        public static readonly RoutedEvent ApplyingStyleEvent = EventManager.RegisterRoutedEvent("ApplyingStyle", RoutingStrategy.Bubble, typeof(ApplyStyleHandler), typeof(SinacorDataGrid));
        /// <summary>
        /// Evento disparado depois do inicio da aplicação de um estilo 
        /// </summary>
        public event ApplyStyleHandler ApplyingStyle
        {
            add { AddHandler(ApplyingStyleEvent, value); }
            remove { RemoveHandler(ApplyingStyleEvent, value); }
        }

        /// <summary>
        /// Dispara o evento <c>ApplyingStyle</c>
        /// </summary>
        /// <param name="element">Elemento que vai disparar o evento</param>
        /// <param name="index">Índice do item</param>
        /// <param name="item">Item</param>
        /// <returns>Estilo a ser aplicado</returns>
        protected virtual string OnApplyingStyle(int index, object item)
        {
            ApplyStyleEventArgs e = new ApplyStyleEventArgs(ApplyingStyleEvent, this, new ItemInfo(index, item));
            this.RaiseEvent(e);
            return e.Style;
        }
        #endregion

        #region ContextMenu

        #region ContextMenuTemplate
        public static readonly DependencyProperty ContextMenuTemplateProperty = DependencyProperty.Register("ContextMenuTemplate", typeof(DataTemplate), typeof(SinacorDataGrid), new FrameworkPropertyMetadata(null));
        /// <summary>
        /// Template do menu de contexto da grid
        /// </summary>
        public DataTemplate ContextMenuTemplate
        {
            get { return (DataTemplate)GetValue(ContextMenuTemplateProperty); }
            set { SetValue(ContextMenuTemplateProperty, value); }
        }
        #endregion

        #region ContextMenuTemplateSelector
        public static readonly DependencyProperty ContextMenuTemplateSelectorProperty = DependencyProperty.Register("ContextMenuTemplateSelector", typeof(DataTemplateSelector), typeof(SinacorDataGrid), new FrameworkPropertyMetadata(null));
        /// <summary>
        /// TemplateSelector do menu de contexto da grid
        /// </summary>
        public DataTemplateSelector ContextMenuTemplateSelector
        {
            get { return (DataTemplateSelector)GetValue(ContextMenuTemplateSelectorProperty); }
            set { SetValue(ContextMenuTemplateSelectorProperty, value); }
        }
        #endregion

        #endregion

        #region Selection

        #region SelectFirstItemCommand

        #region SelectFirstItemCommand_CanExecute
        private void SelectFirstItemCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            e.CanExecute = grid.CanSelectFirstItem();
            e.Handled = true;
        }
        #endregion

        #region SelectFirstItemCommand_Executed
        private void SelectFirstItemCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.SelectFirstItem();
        }
        #endregion

        #endregion

        #region SelectPreviousItemCommand

        #region SelectPreviousItemCommand_CanExecute
        private void SelectPreviousItemCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            e.CanExecute = grid.CanSelectPreviousItem();
            e.Handled = true;
        }
        #endregion

        #region SelectPreviousItemCommand_Executed
        private void SelectPreviousItemCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.SelectPreviousItem();
        }
        #endregion

        #endregion

        #region SelectNextItemCommand

        #region SelectNextItemCommand_CanExecute
        private void SelectNextItemCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            e.CanExecute = grid.CanSelectNextItem();
            e.Handled = true;
        }
        #endregion

        #region SelectNextItemCommand_Executed
        private void SelectNextItemCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.SelectNextItem();
        }
        #endregion

        #endregion

        #region SelectLastItemCommand

        #region SelectLastItemCommand_CanExecute
        private void SelectLastItemCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            e.CanExecute = grid.CanSelectLastItem();
            e.Handled = true;
        }
        #endregion

        #region SelectLastItemCommand_Executed
        private void SelectLastItemCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.SelectLastItem();
        }
        #endregion

        #endregion

        #region SelectFirstItem
        /// <summary>
        /// Indica se pode selecionar o primeiro item
        /// </summary>
        /// <returns>true se pode selecionar o item, false se não puder</returns>
        protected bool CanSelectFirstItem()
        {
            return (this.HasItems() && this.SelectedIndex != 0);
        }

        /// <summary>
        /// Seleciona o primeiro item
        /// </summary>
        protected void SelectFirstItem()
        {
            if (this.CanSelectFirstItem())
            {
                this.SelectedIndex = 0;
                this.ScrollIntoView(this.SelectedItem);
                this.CurrentItem = this.SelectedItem;
            }
        }
        #endregion

        #region SelectPreviousItem
        /// <summary>
        /// Indica se pode selecionar o item anterior
        /// </summary>
        /// <returns>true se pode selecionar o item, false se não puder</returns>
        protected bool CanSelectPreviousItem()
        {
            return (this.HasItems() && this.SelectedIndex != 0);
        }

        /// <summary>
        /// Seleciona o item anterior
        /// </summary>
        protected void SelectPreviousItem()
        {
            if (this.CanSelectPreviousItem())
            {
                if (this.SelectedIndex == -1)
                {
                    this.SelectFirstItem();
                }
                else if (this.SelectedIndex > 0)
                {
                    this.SelectedIndex = this.SelectedIndex - 1;
                    this.ScrollIntoView(this.SelectedItem);
                    this.CurrentItem = this.SelectedItem;
                }
            }
        }
        #endregion

        #region SelectNextItem
        /// <summary>
        /// Indica se pode selecionar o próximo item
        /// </summary>
        /// <returns>true se pode selecionar o item, false se não puder</returns>
        protected bool CanSelectNextItem()
        {
            return (this.HasItems() && this.SelectedIndex < this.GetItemsSourceList().Count - 1);
        }

        /// <summary>
        /// Seleciona o próximo item
        /// </summary>
        protected void SelectNextItem()
        {
            if (this.CanSelectNextItem())
            {
                if (this.SelectedIndex == -1)
                {
                    this.SelectFirstItem();
                }
                else if (this.SelectedIndex < this.GetItemsSourceList().Count - 1)
                {
                    this.SelectedIndex = this.SelectedIndex + 1;
                    this.ScrollIntoView(this.SelectedItem);
                    this.CurrentItem = this.SelectedItem;
                }
            }
        }
        #endregion

        #region SelectLastItem
        /// <summary>
        /// Indica se pode selecionar o último item
        /// </summary>
        /// <returns>true se pode selecionar o item, false se não puder</returns>
        protected bool CanSelectLastItem()
        {
            return (this.HasItems() && this.SelectedIndex < this.GetItemsSourceList().Count - 1);
        }

        /// <summary>
        /// Seleciona o último item
        /// </summary>
        protected void SelectLastItem()
        {
            if (this.CanSelectLastItem())
            {
                this.SelectedIndex = this.GetItemsSourceList().Count - 1;
                this.ScrollIntoView(this.SelectedItem);
                this.CurrentItem = this.SelectedItem;
            }
        }
        #endregion
        
        #endregion

        #region CopyAllClipboardCommand

        #region CopyAllClipboardCommand_CanExecute
        private void CopyAllClipboardCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;

            e.CanExecute = ClipboardCopyMode != Microsoft.Windows.Controls.DataGridClipboardCopyMode.None && this.HasItems();
            e.Handled = true;
        }
        #endregion

        #region CopyAllClipboardCommand_Executed
        private void CopyAllClipboardCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            SinacorDataGrid grid = (SinacorDataGrid)sender;
            grid.SelectAll();
            grid.OnExecutedCopy(e);
        }
        #endregion

        #endregion

        #region GetItemType
        /// <summary>
        /// Captura o type do item da coleção
        /// </summary>
        /// <returns>Type do item</returns>
        private Type GetItemType()
        {
            Type type = null;

            if (this.ItemsSource != null)
            {
                if (this.ItemsSource.GetType().IsGenericType)
                {
                    type = this.ItemsSource.GetType().GetGenericArguments()[0];
                }
                else
                {
                    IEnumerator enumerator = this.ItemsSource.GetEnumerator();

                    if (enumerator.MoveNext())
                    {
                        type = enumerator.Current.GetType();
                    }
                }
            }

            return type;
        }
        #endregion

        #region GetItemsSourceList
        /// <summary>
        /// Retorna ItemsSource convertido para IList
        /// </summary>
        private IList GetItemsSourceList()
        {
            return this.ItemsSource as IList;
        }

        /// <summary>
        /// Retorna ItemsSource convertido para IList
        /// </summary>
        private bool HasItems()
        {
            return this.GetItemsSourceList() != null && this.GetItemsSourceList().Count > 0;
        }
        #endregion

        #region IConfigurationComponent Members

        #region LoadConfiguration
        void IConfigurationComponent<SinacorConfigurationObjectType>.LoadConfiguration(IConfigurationObject<SinacorConfigurationObjectType> config)
        {
            if (config == null)
                throw new ArgumentNullException("config");
            if (!(config is DataGridConfigurationObject))
                throw new ArgumentException("The type of configuration object must be DataGridConfigurationObject", "config");

            DataGridConfigurationObject dataGridConfiguration = (DataGridConfigurationObject)config;

            // Configurações das colunas
            foreach (ColumnConfigurationObject columnConfiguration in dataGridConfiguration.Columns)
            {
                // Capturando coluna
                Microsoft.Windows.Controls.DataGridColumn column = this.Columns[columnConfiguration.ConfigurationName];
                if (column == null)
                    throw new InvalidOperationException(string.Format("Column name '{0}' not found", columnConfiguration.ConfigurationName));

                // Indica se a coluna está visivel
                if (((IDataGridColumn)column).CanUserChangeVisibility && columnConfiguration.Visibility != null)
                    column.Visibility = columnConfiguration.Visibility.Value;

				// Posição visual da coluna
				if (columnConfiguration.DisplayIndex >= 0)
					column.DisplayIndex = columnConfiguration.DisplayIndex;

                // Largura da coluna
                if (!string.IsNullOrEmpty(columnConfiguration.Width))
                    column.Width = (Microsoft.Windows.Controls.DataGridLength)new Microsoft.Windows.Controls.DataGridLengthConverter().ConvertFromString(null, CultureInfo.InvariantCulture, columnConfiguration.Width);
            }

            // Ordenação
            var sortedColumns =
                from c in dataGridConfiguration.Columns
                where c.SortDirection != null
                orderby c.SortIndex
                select new { c.ConfigurationName, c.SortDirection };

            foreach (var col in sortedColumns)
            {
                this.Columns[col.ConfigurationName].SortDirection = (ListSortDirection)col.SortDirection;
            }

            this.SortExpression = dataGridConfiguration.SortExpression;

            // Número de colunas fixas
            if (dataGridConfiguration.FrozenColumnCount > -1)
                this.FrozenColumnCount = dataGridConfiguration.FrozenColumnCount;
        }
        #endregion

        #region GetConfiguration
        IConfigurationObject<SinacorConfigurationObjectType> IConfigurationComponent<SinacorConfigurationObjectType>.GetConfiguration()
        {
            DataGridConfigurationObject dataGridConfiguration = new DataGridConfigurationObject();

            dataGridConfiguration.ConfigurationName = this.Name;

            // Configurações das colunas
            foreach (Microsoft.Windows.Controls.DataGridColumn column in this.Columns)
            {
                ColumnConfigurationObject columnConfiguration = new ColumnConfigurationObject();

                // Nome da coluna
                columnConfiguration.ConfigurationName = ((IDataGridColumn)column).Name;

                // Indica se a coluna está visivel
                columnConfiguration.Visibility = (((IDataGridColumn)column).CanUserChangeVisibility ? column.Visibility : (System.Windows.Visibility?)null);
                // Posição visual da coluna
                columnConfiguration.DisplayIndex = column.DisplayIndex;

                // Largura da coluna
                columnConfiguration.Width = new Microsoft.Windows.Controls.DataGridLengthConverter().ConvertToString(null, CultureInfo.InvariantCulture, column.Width);

                // Ordenação
                columnConfiguration.SortDirection = column.SortDirection;
                columnConfiguration.SortIndex = ((IDataGridColumn)column).SortIndex;

                dataGridConfiguration.Columns.Add(columnConfiguration);
            }

            // Ordenação
            dataGridConfiguration.SortExpression = this.SortExpression;

            // Número de colunas fixas
            dataGridConfiguration.FrozenColumnCount = this.FrozenColumnCount;

            return dataGridConfiguration;
        }
        #endregion

        #endregion

        #region DragDrop

        #region IItemsControlDragSource Members

        IList IItemsControlDragSource.GetDraggedItems()
        {
            return this.SelectedItems;
        }

        #endregion

        #endregion
    }
}
